#include "updateutil.h"
#include <QTimer>
#include "downloader.h"
#include "enetwork.h"
#include "dbapp.h"
#include "ycompress.h"
#include <QDate>
#include <QDirIterator>
#include <QJsonDocument>
#include <QJsonObject>
#include "machineutil.h"
#include "mylogger.h"

using namespace ns_yht;

UpdateUtil *UpdateUtil::g_UpdateUtil = nullptr;

namespace
{
#define baseData_Code "BaseDataForOffline"
}

UpdateUtil::UpdateUtil(const QVector<QPair<QString, QString>> &softwareList, const QString &appDir, bool needLoop) : m_needLoop(needLoop), m_appDir(appDir)
{
    g_UpdateUtil = this;
    if (softwareList.count() > 0)
    {
        auto software = softwareList.at(0);
        appscan.reset(new SoftwareScan(software.first, software.second));
        connect(appscan.data(), &SoftwareScan::finished, this, &UpdateUtil::onScanFinished);
    }
    // baseDatascan.reset(new SoftwareScan(baseData_Code, "0.0.1"));
    // connect(baseDatascan.data(), &SoftwareScan::finished, this, &UpdateUtil::onScanFinished);
}

UpdateUtil::~UpdateUtil()
{
    if (m_pTimer)
    {
        m_pTimer->stop();
        m_pTimer->deleteLater();
    }
}

UpdateUtil *UpdateUtil::instance()
{
    return g_UpdateUtil;
}

SoftwareScan *UpdateUtil::getAppScan()
{
    return appscan.data();
}

// SoftwareScan *UpdateUtil::getBaseDataScan()
// {
//     return baseDatascan.data();
// }

bool UpdateUtil::needUpdate() const
{
    return (appscan->getModel()->state == VersionScanResult::NeedUpdate /* || baseDatascan->getModel()->state == VersionScanResult::NeedUpdate*/);
}

void UpdateUtil::startScan()
{
    appscan->start();
    // baseDatascan->start();
}

void UpdateUtil::onScanFinished()
{

    if (appscan->getModel()->state != VersionScanResult::Unknown)
        emit scanFinished();

    if (m_needLoop && appscan->getModel()->state != VersionScanResult::NeedUpdate /*&& appscan->state() != 0*/)
    {
        if (!m_pTimer)
        {
            m_pTimer = new QTimer(this);
            connect(m_pTimer, &QTimer::timeout, this, [=]
                    { appscan->start(); });
        }

        if (!m_pTimer->isActive())
            m_pTimer->start(120000);
    }
    else
    {
        if (m_pTimer)
            m_pTimer->stop();
    }
}

void UpdateUtil::updateAll()
{
    if (!needUpdate())
        return;
    if (m_downloder.isNull())
    {
        m_downloder.reset(new Downloader(ENetwork::getManager(), m_appDir));
        connect(m_downloder.data(), SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadProgress(qint64, qint64)));
        connect(m_downloder.data(), &Downloader::finished, this, &UpdateUtil::onDownloadFinished);
    }
    bool downloading = false;

    if (!appscan->getModel()->updated)
    {
        downloading = true;
        m_downloadingModel = appscan->getModel();
        m_downloder->start(appscan->getModel()->fileName, appscan->getModel()->url);
    }

    if (downloading)
        return;

    if (!downloading)
        emit downloadFinished();
}

QString UpdateUtil::getDownloadingFileName() const
{
    if (m_downloadingModel.isNull())
        return "";
    return m_downloadingModel->fileName;
}

void UpdateUtil::onDownloadProgress(qint64 a, qint64 b)
{
    if (a < 0 || b <= 0)
        return;
    qint64 s = int(a * 1.0 / b * 100);

    emit downloadProgress(s);
}

void UpdateUtil::onDownloadFinished(bool isSucceed)
{
    if (m_downloadingModel.isNull())
    {
        if (GLOG)
            GLOG->info("onDownloadFinished: m_downloadingFile is null");
        emit downloadFinished();
        return;
    }

    m_downloadingModel->updated = true;

    if (isSucceed /*&& (!DBAPP || DBAPP->UpdateFileInfo(m_downloadingFile))*/)
    {
        postUpdateLog(m_downloadingModel.data(), 1);
        updateAll();
    }
    else
    {
        postUpdateLog(m_downloadingModel.data(), 0);
        resetFiles();
        emit updateFailed();
    }
}

void UpdateUtil::resetFiles()
{
    QString path = m_appDir;
    QStringList filters;
    filters << "*.old";

    QDirIterator dir_it(path, filters, QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
    while (dir_it.hasNext())
    {
        dir_it.next();
        QFileInfo file_info = dir_it.fileInfo();
        QString full_path = file_info.absoluteFilePath();

        QString preFile = full_path.left(full_path.length() - 4);
        if (QFile::exists(preFile))
            QFile::remove(preFile);
        QFile::rename(full_path, preFile);
    }

    QStringList filters1;
    filters1 << "*.new";

    QDirIterator dir_it1(path, filters1, QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
    while (dir_it1.hasNext())
    {
        dir_it1.next();
        QFileInfo file_info = dir_it1.fileInfo();
        QString full_path = file_info.absoluteFilePath();

        QFile::remove(full_path);
    }
}

void UpdateUtil::postUpdateLog(ModelSoftware *software, int result)
{
    QJsonObject obj;
    obj.insert("machineCode", MachineUtil::machineCode());
    obj.insert("softwareCode", software->code);
    obj.insert("oldVersion", software->currentVersion.toString());
    obj.insert("newVersion", software->remoteVersion.toString());
    obj.insert("result", result);

    QNetworkReply *reply = ENetwork::PostWithJson(QJsonDocument(obj).toJson(), "http://restapi.ehanghai.cn/xxyc-api/updateLog", {}, {}, true);
    if (reply)
        connect(reply, &QNetworkReply::finished, this, [=]
                { onUpdateLogFinished(reply); });
}

void UpdateUtil::onUpdateLogFinished(QNetworkReply *reply)
{
    if (ENetwork::checkReplyError(reply))
    {
        return;
    }
    const QJsonDocument &jsonDocument = QJsonDocument::fromJson(reply->readAll());
    reply->deleteLater();

    if (!jsonDocument.isNull())
    {
        const QJsonObject &rootObj = jsonDocument.object();
        if (rootObj.value("success").toBool())
        {
            if (GLOG)
                GLOG->info("updateLog Finished -- ok");
        }
        else
        {
            if (GLOG)
                GLOG->info("updateLog Finished - failed - {}", rootObj.value("errorMsg").toString().toStdString());
        }
    }
    emit postlogFinished();
}
